#ifndef PW_PBL_CHARCONV_HPP
#define PW_PBL_CHARCONV_HPP

#include <algorithm>
#include <concepts>
#include <numeric>
#include <string_view>

namespace pw_pbl::CharConv
{
	template <bool WithSign = true, bool... IsSigned> requires(WithSign ? sizeof...(IsSigned) <= 1 : sizeof...(IsSigned) == 0)
	constexpr const char *CheckFormat(const char *begin, const char *end) noexcept
	{
		if constexpr (WithSign)
		{
			if (end <= begin)
				return begin;
			if constexpr ((IsSigned && ...))
			{
				if (auto sn = *begin; sn != '-' && sn != '+' && !std::isdigit(sn))
					return begin;
			}
			else
			{
				if (auto sn = *begin; sn != '+' && !std::isdigit(sn))
					return begin;
			}
			return CheckFormat<false>(begin + 1, end);
		}
		else
			return std::find_if_not(begin, end, isdigit);
	}

	template <bool WithSign = true, bool... IsSigned>
	constexpr const char *CheckFormat(std::string_view text) noexcept { return CheckFormat<WithSign, IsSigned...>(text.begin(), text.end()); }

	template <bool IsSigned = true>
	constexpr std::conditional_t<IsSigned, bool, void> RemoveSign(const char *&begin, const char *end) noexcept
	{
		if constexpr (IsSigned)
		{
			bool isNeg;
			if (end > begin)
			{
				isNeg = *begin == '-';
				if (isNeg || *begin == '+')
					begin++;
			}
			else
				isNeg = false;
			return isNeg;
		}
		else
		{
			if (end > begin && *begin == '+')
				begin++;
		}
	}

	template <std::unsigned_integral REP, bool WithSign = true>
	constexpr REP fast_from_char(const char *begin, const char *end) noexcept
	{
		if constexpr (sizeof(REP) <= sizeof(size_t) && !std::same_as<REP, size_t>)
			return fast_from_char<size_t, WithSign>(begin, end);
		else if constexpr (WithSign)
		{
			RemoveSign<false>(begin, end);
			return fast_from_char<REP, false>(begin, end);
		}
		else
			return std::reduce(begin, end, REP(0), [](REP result, char ch) { return result * 10 + ch - '0'; });
	}

	template <std::signed_integral REP, bool WithSign = true>
	constexpr REP fast_from_char(const char *begin, const char *end) noexcept
	{
		using ssize_t = std::make_signed_t<size_t>;
		if constexpr (sizeof(REP) <= sizeof(ssize_t) && !std::same_as<REP, ssize_t>)
			return fast_from_char<ssize_t, WithSign>(begin, end);
		else if constexpr (WithSign)
		{
			bool isNeg = RemoveSign<true>(begin, end);
			auto result = fast_from_char<std::make_unsigned_t<REP>, false>(begin, end);
			return isNeg ? -result : result;
		}
		else
			return fast_from_char<std::make_unsigned_t<REP>, false>(begin, end);
	}

	template <bool WithSign = true, std::integral REP>
	constexpr REP fast_from_char(std::string_view view) noexcept { return fast_from_char<REP>(view.begin(), view.end()); }

	template <bool WithSign = true, std::integral REP>
	constexpr void fast_from_char(const char *begin, const char *end, REP &out) noexcept { out = fast_from_char<REP>(begin, end); }

	template <bool WithSign = true, std::integral REP>
	constexpr void fast_from_char(std::string_view view, REP &out) noexcept { out = fast_from_char<REP>(view.begin(), view.end()); }

} // namespace pw_pbl::CharConv

#endif // PW_PBL_CHARCONV_HPP
